#include "daemon.h"
#include "log.h"
#include <ctime>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "util.h"
#include <sstream>

// Done

int g_daemon_restart_interval = 5;

std::string ProcessInfo::toString() const
{
    std::stringstream ss;
    ss << "[ProcessInfo parent_id=]" << parent_id
       << " main_id=" << main_id
       << " parent_start_time=" << Time2Str(parent_start_time)
       << " main_start_time=" << Time2Str(main_start_time)
       << " restart_count=" << restart_count << "]";

    return ss.str();
}

static int real_start(int argc, char **argv, std::function<int(int argc, char **argv)> main_cb)
{
    return main_cb(argc, argv);
}

// int daemon(int nochdir, int noclose);
// nochdir：如果设置为0，则将当前工作目录更改为根目录（/）；如果设置为1，则保持当前工作目录不变。
// noclose：如果设置为0，则关闭标准输入、输出和错误文件描述符；如果设置为1，则保留这些文件描述符。

static int real_daemon(int argc, char **argv, std::function<int(int argc, char **argv)> main_cb)
{
    daemon(1, 0);
    ProcessInfoMgr::GetInstance()->parent_id = getpid();
    ProcessInfoMgr::GetInstance()->parent_start_time = time(0);
    while (true)
    {
        pid_t pid = fork();
        if (pid == 0)
        {
            // 子进程返回
            ProcessInfoMgr::GetInstance()->main_id = getpid();
            ProcessInfoMgr::GetInstance()->main_start_time = time(0);
            LOG(INFO, "process start pid=", getpid());
            return real_start(argc, argv, main_cb);
        }
        else if (pid < 0)
        {
            LOG(ERROR, "fork fail return = %d errno = %d errstr = %s", pid, errno, strerror(errno));
            return -1;
        }
        else
        {
            // 父进程返回
            int status = 0;
            waitpid(pid, &status, 0);
            if (status)
            {
                LOG(ERROR, "child crash pid=%d status = %d", pid, status);
            }
            else
            {
                LOG(ERROR, "child finished pid=", pid);
                break;
            }
            ProcessInfoMgr::GetInstance()->restart_count += 1;
            sleep(g_daemon_restart_interval);
        }
    }
    return 0;
}

int start_daemon(int argc, char **argv, std::function<int(int argc, char **argv)> main_cb, bool is_daemon)
{
    if (is_daemon)
        return real_daemon(argc, argv, main_cb);
    else
        return real_start(argc, argv, main_cb);
}